package com.linkoog.devtools.code_generator.wizard.generate.ctrl_service;

import com.linkoog.devtools.code_generator.KeyConstants;
import com.linkoog.devtools.code_generator.common.MessageNotification;
import com.linkoog.devtools.code_generator.template.render.engine.TemplateEngine;
import com.linkoog.devtools.code_generator.template.render.engine.TemplateEngineFactory;
import com.linkoog.devtools.code_generator.template.render.engine.TemplateType;
import com.linkoog.devtools.code_generator.util.PsiFileUtil;
import com.linkoog.devtools.code_generator.util.StringUtil;
import com.intellij.ide.util.PackageChooserDialog;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.search.GlobalSearchScope;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.function.Consumer;

public class GenCtrlAndServiceDialog extends DialogWrapper {

    private JPanel myMainPanel;

    private JTextField modelTextField;
    private JTextField packageTextField;

    private JCheckBox controllerCheckBox;
    private JCheckBox serviceCheckBox;
    private JCheckBox serviceImplCheckBox;
    private JButton packageSelectButton;

    private final Project project;
    private final Module module;
    private VirtualFile selectedPackageVF;
    private PsiDirectory basePsiDirectory;

    private final String controllerTemplate;
    private final String serviceTemplate;
    private final String serviceImplTemplate;


    public GenCtrlAndServiceDialog(@NotNull Project project, @NotNull Module module, @NotNull VirtualFile selectedPackageVF) {
        super(true);
        this.project = project;
        this.module = module;


        this.controllerTemplate = getTemplateContext("ctrl_service/Controller.java.vm");
        this.serviceTemplate = getTemplateContext("ctrl_service/Service.java.vm");
        this.serviceImplTemplate = getTemplateContext("ctrl_service/ServiceImpl.java.vm");

        setTitle("创建Controller和Service类");
        setResizable(false);
        myMainPanel.setMinimumSize(new Dimension(300, 150));

        initBasePackage(project, selectedPackageVF);
        init();
    }

    private void initBasePackage(@NotNull Project project, @NotNull VirtualFile selectedPackageVF) {
        final String name = selectedPackageVF.getName();
        if ("controller".equals(name)){
            selectedPackageVF = selectedPackageVF.getParent();
        }

        ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(project).getFileIndex();
        String selectedPackageName = projectFileIndex.getPackageNameByDirectory(selectedPackageVF);
        if (StringUtils.isBlank(selectedPackageName)) {
            selectedPackageName = "<default>";
        }

        this.selectedPackageVF = selectedPackageVF;
        this.basePsiDirectory = PsiManager.getInstance(project).findDirectory(this.selectedPackageVF);

        packageTextField.setText(selectedPackageName);
        packageTextField.setEditable(false);
        packageSelectButton.addActionListener(e -> {
            chooserPackage(packageTextField.getText(), psiPackage -> {
                PsiDirectory[] psiDirectories = psiPackage.getDirectories(GlobalSearchScope.moduleRuntimeScope(this.module,false));
                if (psiDirectories.length == 1){
                    this.basePsiDirectory = psiDirectories[0];
                    packageTextField.setText(psiPackage.getQualifiedName());
                }
            });
        });
    }

    /**
     * 选择包名
     *
     * @param defaultSelect 默认选中包名
     * @param consumer      完成事件
     */
    private void chooserPackage(String defaultSelect, Consumer<PsiPackage> consumer) {
        PackageChooserDialog chooser = new PackageChooserDialog("请选择package包", module);
        chooser.selectPackage(defaultSelect);
        chooser.show();
        PsiPackage psiPackage = chooser.getSelectedPackage();
        if (psiPackage != null) {
            consumer.accept(psiPackage);
        }
        chooser.getDisposable().dispose();
    }


    @Override
    public void doCancelAction() {
        super.doCancelAction();
    }

    @Override
    protected void doOKAction() {
        String model = modelTextField.getText();
        if (StringUtil.isBlank(model)) {
            Messages.showErrorDialog(myMainPanel, "module不能为空", "错误");
            return;
        }

        final String entityName = handlerEntityName(model);
        HashMap<String, Object> dataMap = new HashMap<>();
        dataMap.put(KeyConstants.AUTHOR, System.getProperty("user.name"));
        dataMap.put(KeyConstants.DATE, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        dataMap.put(KeyConstants.REMARK, "DevTools-代码生成器");
        dataMap.put("EntityName", entityName);
        dataMap.put("basePackage", packageTextField.getText());

        ApplicationManager.getApplication().invokeLater(() -> ApplicationManager.getApplication().runReadAction(() -> {
            TemplateEngine templateEngine = TemplateEngineFactory.getTemplateEngine(TemplateType.VELOCITY);
            List<PsiFileUtil.CreateFileParam> createFileParams = new ArrayList<>();
            if (controllerCheckBox.isSelected()) {
                try {
                    String context = templateEngine.render(controllerTemplate, dataMap);
                    createFileParams.add(new PsiFileUtil.CreateFileParam("/controller", entityName + "Controller.java", context));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            if (serviceCheckBox.isSelected()) {
                try {
                    String context = templateEngine.render(serviceTemplate, dataMap);
                    createFileParams.add(new PsiFileUtil.CreateFileParam("/service", entityName + "Service.java", context));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            if (serviceImplCheckBox.isSelected()) {
                try {
                    String context = templateEngine.render(serviceImplTemplate, dataMap);
                    createFileParams.add(new PsiFileUtil.CreateFileParam("/service/impl", entityName + "ServiceImpl.java", context));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            try {
                PsiFileUtil.createFile(project, basePsiDirectory, createFileParams);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }));
        super.doOKAction();
        MessageNotification.infoNotify("Successfully generated code for you");
    }


    private String handlerEntityName(String model) {
        model = model.trim();
        if (model.length() == 0) {
            return "";
        } else if (model.length() == 1) {
            return model.toUpperCase();
        } else {
            return model.substring(0, 1).toUpperCase() + model.substring(1);
        }
    }

    private String getTemplateContext(String templateName) {
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(templateName);
        if (inputStream == null) {
            return null;
        }
        return readStream(inputStream);
    }


    /**
     * 读取 InputStream 到 String字符串中
     */
    private String readStream(InputStream in) {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[1024];
            int len = -1;
            while ((len = in.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            String content = baos.toString();
            return content;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }


    @Override
    public JComponent createCenterPanel() {
        return myMainPanel;
    }



}
